#!/usr/bin/python
# -*- coding: utf-8 -*-
# Description: 运行任务基类
# Create: 2008-6-1
# Author: MK2[fengmk2@gmail.com]
import time
import datetime
import os
import MySQLdb

class RunTaskBase:
    """连续运行任务基类，适合任务，并且是多进程安全的。
    """
    @property
    def tablename(self):
        raise NotImplementedError('Please define a tablename for this class.')
    
    @property
    def type(self):
        raise NotImplementedError('Please define a type for this class.')
    
    @property
    def limit_num(self):
        return 1000
    
    @property
    def name(self):
        return '%s %d' % (self.__class__.__name__, self.id)
    
    def __init__(self, process_id):
        self.id = process_id
        self.sleeptimes = 0
        self.errorcount = 0
        self.cur_id, self.max_id = None, None
    
    SELECT_INIT_RUN_STATUS = """SELECT cur_id, max_id
                            FROM run_status WHERE process_id=%s AND type=%s"""
    def __init_status(self):
        """获取上次运行状态，当执行被中断后，可以恢复到上次运行状态，继续执行"""
        conn = self._get_connection()
        cursor = conn.cursor()
        cursor.execute(self.SELECT_INIT_RUN_STATUS, (self.id, self.type))
        r = cursor.fetchone()
        if r:
            self.cur_id, self.max_id = r[0], r[1]
            self.info('Got last run status, cur_id: %d, max_id: %d' % (self.cur_id, self.max_id))
    
    def _get_connection(self):
        kwargs = {'host': '192.168.51.170',
                  'user': 'ruser',
                  'passwd': '123456',
                  'db': 'mercury',
                  'charset': 'utf8'}
        conn = MySQLdb.connect(**kwargs)
        return conn
#        return database.get_pool().connection()
    
    SELECT_MIN_ID = 'SELECT id FROM %s ORDER BY id ASC LIMIT 1'
    def get_min_id(self):
        """获取最小记录id"""
        cursor = self._get_connection().cursor()
        cursor.execute(self.SELECT_MIN_ID % self.tablename)
        min_id = cursor.fetchone()[0]
        if not min_id:
            return 1
        return min_id 
    
    SELECT_MAX_ID = 'SELECT id FROM %s ORDER BY id DESC LIMIT 1'
    def get_max_id(self):
        """获取最大记录id"""
        cursor = self._get_connection().cursor()
        cursor.execute(self.SELECT_MAX_ID % self.tablename)
        max_id = cursor.fetchone()[0]
        if not max_id:
            return 1
        return max_id 
    
    SELECT_LAST_STATUS = """SELECT cur_id, max_id
                    FROM run_status type=%s"""
    INSERT_RUN_STATUS = """INSERT INTO run_status(cur_id, max_id, status, process_id, type) 
                                VALUES(%s, %s, %s, %s, %s)"""
    UPDATE_RUN_STATUS = """UPDATE run_status SET cur_id=%s, max_id=%s, status=%s
                            WHERE process_id=%s AND type=%s"""
    SELECT_MAX_ID_STATUS = 'SELECT MAX(max_id) FROM fileslicemgr_run_status WHERE type=%s'
    def __get_task(self):
        """获取任务"""
        if self.cur_id is None or self.max_id is None: #数据库中没有记录，第一次运行
            status = 'First running %s' % datetime.datetime.now()
            self.cursor.execute(self.SELECT_MAX_ID_STATUS, self.type)
            r = self.cursor.fetchone()
            if r[0]: #已存在运行相同任务的进程
                self.__next_task(r[0] + 1)
            else: #这个是第一个进程
                self.__next_task(self.get_min_id())
            self.cursor.execute(self.INSERT_RUN_STATUS, 
                           (self.cur_id, self.max_id, status, self.id, self.type))
        else: # 判断是否结束
            status = 'Still running %s' % datetime.datetime.now()
            if self.cur_id >= self.max_id: #上次任务已完成，分配下一批任务
                self.cursor.execute(self.SELECT_MAX_ID_STATUS, self.type)
                r = self.cursor.fetchone() #肯定会存在的，否则init_status是cur_id会为None
                self.__next_task(r[0] + 1)
                #保存获得的任务
            self.cursor.execute(self.UPDATE_RUN_STATUS, 
                           (self.cur_id, self.max_id, status, self.id, self.type))
        #判断是否完成
        is_continue = True
        if self.cur_id > self.max_id:
            status = 'Finish %s' % datetime.datetime.now()
            self.cursor.execute(self.UPDATE_RUN_STATUS, 
                           (self.cur_id, self.max_id, status, self.id, self.type))
            is_continue = False
        return is_continue
    
    def __next_task(self, next_id):
        self.cur_id = next_id
        self.max_id = next_id + self.limit_num
        max_id = self.get_max_id()
        if self.max_id > max_id: 
            self.max_id = max_id
        
    def run(self):
        while True:
            self.__run_task(self.task)
            self.info('Finished!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
            self.sleeptimes += 1 #增加空闲等到次数，增大等待间隔
            wait_seconds = self.sleeptimes * 30
            self.info('Sleep for %d seconds to restart...' % wait_seconds)
            time.sleep(wait_seconds)
    
    def task(self, cursor):
        """��Ҫ����ʵ��子类需要实现此方法，确定具体运行的逻辑"""
        raise NotImplementedError('task method is not implement...')
    
#    def report_error(self, errormsg, error):
#        try:
#            SendMail(['yuanfeng@kingsoft.com'], 'yuanfeng@kingsoft.com', [],
#                     'Runthread error: %s' % error, errormsg)
#            self.info('Error report had been sent by email.')
#        except: 
#            pass
    
    def __run_task(self, task):
        self.__init_status()
        self.conn = self._get_connection()
        self.cursor = self.conn.cursor()
        while self.__get_task():
            start_time = datetime.datetime.now()
            self.info('Task from %d to %d begin...' % (self.cur_id, self.max_id))
            self.sleeptimes = 0 #重置
            try:
                task(self.cursor)
            except Exception, e:
                self.errorcount += 1
                self.info('Task from %d to %d errors...' % (self.cur_id, self.max_id))
                self.info('Running Error: %s, waiting for %d seconds to again...' % (e, self.errorcount * 30))
                print e
#                self.report_error(errormsg + os.linesep + '%s: cur_id: %d, max_id: %d' % \
#                                                    (self.__class__.__name__, self.cur_id, self.max_id), e)
                time.sleep(self.errorcount * 30)
                
                # 再次确认connection还在
                self.conn = self._get_connection()
                self.cursor = self.conn.cursor()
                continue
            status = 'Task from %d to %d has finished!!!'  % (self.cur_id, self.max_id)
            self.cur_id = self.max_id
            self.info(status)
            self.cursor.execute(self.UPDATE_RUN_STATUS, 
                           (self.cur_id, self.max_id, status, self.id, self.type))
            self.usetime = datetime.datetime.now() - start_time
            self.info('Use time: days: %d, seconds: %d, microseconds: %d' % 
                      (self.usetime.days, self.usetime.seconds, self.usetime.microseconds))
            
    def info(self, msg):
        assert msg is not None
        print '[%s][type:%d]%s: %s' % \
            (datetime.datetime.now().strftime('%H:%M:%S'), 
             self.type, self.name, msg)
